package me.szlx.validation;

import me.szlx.validation.namespace.NameSpace;
import me.szlx.validation.system.ConstraintSystem;

/**
 * 有条件的出错规则。一般地，当条件成立时，则出错。
 */
public interface Validator {
    /**
     * 获取指定约束的校验器。
     *
     * @param constraintCodeOrBrief 约束代码或描述。
     * @return 为指定约束创建新的校验器。
     */
    static Validator of(String constraintCodeOrBrief) {
        return ValidatorFactory.of(constraintCodeOrBrief);
    }

    /**
     * 获取指定约束的校验器。
     *
     * @param constraint 约束代码或描述。
     * @return 为指定约束创建新的校验器。
     */
    static Validator of(Constraint constraint) {
        return ValidatorFactory.of(constraint);
    }

    /**
     * 获取校验的规则。
     *
     * @return 校验的规则。
     */
    Constraint getConstraint();

    /**
     * 立即抛出当前规则的异常。
     */
    default void invalid() {
        throw ConstraintSystem.get().createException(getConstraint());
    }

    /**
     * 立即抛出当前规则的异常。
     *
     * @param nameSpace 使用规则时所处的名称空间。
     */
    default void invalid(NameSpace nameSpace) {
        String constraintCode = nameSpace.decorate(getConstraint().code());
        Constraint constraint = nameSpace != null ? Constraint.of(constraintCode) : getConstraint();
        throw ConstraintSystem.get().createException(constraint);
    }

    /**
     * 立即抛出当前规则的异常。
     *
     * @param cause 导致规则触发异常的原因。
     */
    default void invalid(Throwable cause) {
        throw ConstraintSystem.get().createException(getConstraint(), cause);
    }

    /**
     * 立即抛出当前规则的异常。
     *
     * @param nameSpace 使用规则时所处的名称空间。
     * @param cause     导致规则触发异常的原因。
     */
    default void invalid(NameSpace nameSpace, Throwable cause) {
        String constraintCode = nameSpace.decorate(getConstraint().code());
        Constraint constraint = nameSpace != null ? Constraint.of(constraintCode) : getConstraint();
        throw ConstraintSystem.get().createException(constraint, cause);
    }
    //---------------------


    /**
     * 根据条件触发异常或设什么也不做。
     *
     * @param predicate 触发规则条件。如果为 {code true}， 则触发规则，否则舍什么也不做。
     */
    default void invalidIf(boolean predicate) {
        if (predicate) {
            throw ConstraintSystem.get().createException(getConstraint());
        }
    }

    /**
     * 根据条件触发异常或设什么也不做。
     *
     * @param predicate 触发规则条件。如果为 {code true}， 则触发规则，否则什么也不做。
     * @param nameSpace 规则使用时所处的名称空间。
     */
    default void invalidIf(boolean predicate, NameSpace nameSpace) {
        if (predicate) {
            String constraintCode = nameSpace.decorate(getConstraint().code());
            Constraint constraint = nameSpace != null ? Constraint.of(constraintCode) : getConstraint();
            throw ConstraintSystem.get().createException(constraint);
        }
    }

    /**
     * 根据条件触发异常或设什么也不做。
     *
     * @param conditional 触发规则条件。如果条件应用结果为 {code true}， 则触发规则，否则什么也不做。
     */
    default void invalidIf(Conditional conditional) {
        Assert.notNull(conditional, "规则条件不能为null");
        invalidIf(conditional.apply());
    }

    /**
     * 根据条件触发异常或设什么也不做。
     *
     * @param conditional 触发规则条件。如果条件应用结果为 {code true}， 则触发规则，否则什么也不做。
     * @param nameSpace   规则使用时所处的名称空间。
     */
    default void invalidIf(Conditional conditional, NameSpace nameSpace) {
        Assert.notNull(conditional, "规则条件不能为null");
        invalidIf(conditional.apply(), nameSpace);
    }

    static void invalid(String constraintCodeOrBrief) {
        Assert.constraintNotNull(constraintCodeOrBrief);
        of(constraintCodeOrBrief).invalid();
    }

    static void invalid(String constraintCodeOrBrief, NameSpace nameSpace) {
        Assert.constraintNotNull(constraintCodeOrBrief);
        of(constraintCodeOrBrief).invalid(nameSpace);
    }

    static void invalid(String constraintCodeOrBrief, Throwable throwable) {
        Assert.constraintNotNull(constraintCodeOrBrief);
        of(constraintCodeOrBrief).invalid(throwable);
    }

    static void invalid(String constraintCodeOrBrief, NameSpace nameSpace, Throwable throwable) {
        Assert.constraintNotNull(constraintCodeOrBrief);
        of(constraintCodeOrBrief).invalid(nameSpace, throwable);
    }

    static void invalid(Constraint constraint) {
        Assert.constraintNotNull(constraint);
        of(constraint).invalid();
    }

    static void invalid(Constraint constraint, NameSpace nameSpace) {
        Assert.constraintNotNull(constraint);
        of(constraint).invalid(nameSpace);
    }

    static void invalid(Constraint constraint, Throwable throwable) {
        Assert.constraintNotNull(constraint);
        of(constraint).invalid(throwable);
    }

    static void invalid(Constraint constraint, NameSpace nameSpace, Throwable throwable) {
        Assert.constraintNotNull(constraint);
        of(constraint).invalid(nameSpace, throwable);
    }

    static void invalidIf(boolean predicate, String constraintCodeOrBrief) {
        if (predicate) {
            invalid(constraintCodeOrBrief);
        }
    }

    static void invalidIf(boolean predicate, String constraintCodeOrBrief, NameSpace nameSpace) {
        if (predicate) {
            invalid(constraintCodeOrBrief, nameSpace);
        }
    }

    static void invalidIf(boolean predicate, Constraint constraint) {
        Assert.constraintNotNull(constraint);
        if (predicate) {
            invalid(constraint);
        }
    }

    static void invalidIf(boolean predicate, Constraint constraint, NameSpace nameSpace) {
        Assert.constraintNotNull(constraint);
        if (predicate) {
            invalid(constraint, nameSpace);
        }
    }

    static void invalidIf(Conditional conditional, String constraintCodeOrBrief) {
        Assert.notNull(conditional, "校验约束不能为null");
        invalidIf(conditional.apply(), constraintCodeOrBrief);
    }

    static void invalidIf(Conditional conditional, String constraintCodeOrBrief, NameSpace nameSpace) {
        Assert.notNull(conditional, "校验约束不能为null");
        invalidIf(conditional.apply(), constraintCodeOrBrief, nameSpace);
    }

    static void invalidIf(Conditional conditional, Constraint constraint) {
        Assert.constraintNotNull(constraint);
        Assert.conditionalNotNull(conditional);
        invalidIf(conditional.apply(), constraint);
    }

    static void invalidIf(Conditional conditional, Constraint constraint, NameSpace nameSpace) {
        Assert.constraintNotNull(constraint);
        Assert.conditionalNotNull(conditional);
        invalidIf(conditional.apply(), constraint, nameSpace);
    }
}
